Skip to content

Commit

Permalink
Merge pull request #69 from uqbar-project/updated-visuals
Browse files Browse the repository at this point in the history
Invisible objects and objects with text
  • Loading branch information
PalumboN authored Aug 27, 2021
2 parents 350f61c + bd0b098 commit dab9568
Show file tree
Hide file tree
Showing 7 changed files with 19,436 additions and 45 deletions.
19,314 changes: 19,300 additions & 14 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"typescript": "^4.2.3",
"use-interval": "^1.2.1",
"uuid": "^3.4.0",
"wollok-ts": "file:../wollok-ts/wollok-ts-3.0.4.tgz",
"wollok-ts": "3.0.6",
"xml-parser": "^1.2.1"
},
"scripts": {
Expand Down
64 changes: 55 additions & 9 deletions src/components/game/Sketch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import validate from 'wollok-ts/dist/validator'
import { Interpreter } from 'wollok-ts/dist/interpreter/interpreter'
import { GameProject, DEFAULT_GAME_ASSETS_DIR } from './gameProject'
import { GameSound, SoundState, SoundStatus } from './GameSound'
import { buildKeyPressEvent, visualState, flushEvents, canvasResolution, queueEvent } from './SketchUtils'
import { Button } from '@material-ui/core'
import { buildKeyPressEvent, visualState, flushEvents, canvasResolution, queueEvent, Position } from './SketchUtils'
import { Button, Size } from '@material-ui/core'
import ReplayIcon from '@material-ui/icons/Replay'
import { DrawableMessage, drawMessage } from './messages'
import { DrawableMessage, drawMessage, TEXT_SIZE, TEXT_STYLE } from './messages'
import { CenterFocusStrong } from '@material-ui/icons'

const { round } = Math

Expand Down Expand Up @@ -41,6 +42,32 @@ function wKeyCode(key: string, keyCode: number): string {
return '' //If an unknown key is pressed, a string should be returned
}

function write(sketch: p5, drawableText: DrawableText) {
const defaultTextColor = 'blue'
const grey = '#1c1c1c'
const hAlign = drawableText.horizAlign || 'center'
const vAlign = drawableText.vertAlign || 'center'
const x = drawableText.position.x
const y = drawableText.position.y
sketch.textSize(drawableText.size || TEXT_SIZE)
sketch.textStyle(drawableText.style || TEXT_STYLE)
sketch.textAlign(hAlign, vAlign)
sketch.stroke(grey)
sketch.fill(drawableText.color || defaultTextColor)
sketch.text(drawableText.text, x, y)
}

function hexaToColor(textColor?: string) { return !textColor ? undefined : '#' + textColor }
interface DrawableText {
position: Position;
text: string;
color?: string;
size?: number;
horizAlign?: p5.HORIZ_ALIGN;
vertAlign?: p5.VERT_ALIGN;
style?: p5.THE_STYLE;
}

interface SketchProps {
gameProject: GameProject
evaluation: Evaluation
Expand Down Expand Up @@ -119,18 +146,37 @@ function render(interpreter: Interpreter, sketch: p5, images: Map<string, p5.Ima

const messagesToDraw: DrawableMessage[] = []
for (const visual of game.get('visuals')?.innerCollection ?? []) {
const { image: stateImage, position, message } = visualState(interpreter, visual)
const imageObject = image(stateImage)
const x = position.x * cellPixelSize
const y = sketch.height - position.y * cellPixelSize - imageObject.height

sketch.image(imageObject, x, y)
const { image: stateImage, position, message, text, textColor } = visualState(interpreter, visual)
const imageObject = stateImage === undefined ? stateImage : image(stateImage)
let x = position.x * cellPixelSize
let y = sketch.height - (position.y + 1) * cellPixelSize

if (imageObject) {
x = position.x * cellPixelSize
y = sketch.height - position.y * cellPixelSize - imageObject.height
sketch.image(imageObject, x, y)
const defaultImage = image()
if (imageObject == defaultImage) {
const drawableText = {color: 'black', horizAlign: sketch.LEFT,
vertAlign: sketch.TOP, text: 'IMAGE\n NOT\nFOUND', position: {x, y}}
write(sketch, drawableText)
}
}

if (message && visual.get('messageTime')!.innerNumber! > sketch.millis())
messagesToDraw.push({ message, x, y })

if (text) {
x = (position.x + 0.5) * cellPixelSize
y = sketch.height - (position.y + 0.5) * cellPixelSize
const drawableText = {text, position: {x, y}, color: hexaToColor(textColor)}
write(sketch, drawableText)
}
}

messagesToDraw.forEach(drawMessage(sketch))


}

// ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Expand Down
19 changes: 16 additions & 3 deletions src/components/game/SketchUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { Interpreter } from 'wollok-ts/dist/interpreter/interpreter'

const { round } = Math

function invokeMethod(interpreter: Interpreter, visual: RuntimeObject, method: string) {
const lookedUpMethod = visual.module.lookupMethod(method, 0)
return lookedUpMethod && interpreter.invoke(lookedUpMethod, visual)!.innerString
}

export function wKeyCode(keyName: string, keyCode: number): string { //These keyCodes correspond to http://keycode.info/
if (keyCode >= 48 && keyCode <= 57) return `Digit${keyName}` //Numbers (non numpad)
if (keyCode >= 65 && keyCode <= 90) return `Key${keyName.toUpperCase()}` //Letters
Expand Down Expand Up @@ -30,18 +35,26 @@ export function buildKeyPressEvent(interpreter: Interpreter, keyCode: string): R

export interface VisualState {
image?: string;
position: { x: number; y: number };
position: Position;
message?: string;
text?: string;
textColor?: string;
}
export interface Position {
x: number;
y: number;
}

export function visualState(interpreter: Interpreter, visual: RuntimeObject): VisualState {
const image = interpreter.send('image', visual)!.innerString
const image = invokeMethod(interpreter, visual, 'image')
const text = invokeMethod(interpreter, visual, 'text')
const textColor = invokeMethod(interpreter, visual, 'textColor')
const position = interpreter.send('position', visual)!
const roundedPosition = interpreter.send('round', position)!
const x = roundedPosition.get('x')!.innerNumber!
const y = roundedPosition.get('y')!.innerNumber!
const message = visual.get('message')?.innerString
return { image, position: { x, y }, message }
return { image, position: { x, y }, text, textColor, message }
}

export function flushEvents(interpreter: Interpreter, ms: number): void {
Expand Down
15 changes: 15 additions & 0 deletions src/components/game/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,17 @@ export interface MessageDrawer {
textWidth(message: string): number;
rect(xPos: number, yPos: number, xSize: number, ySize: number, tl?: number, tr?: number, br?: number, bl?: number): void;
text(message: string, xPos: number, yPos: number, xLimit: number, yLimit: number): void;
fill(color: string): void;
textAlign(alignment: string): void;
textSize(size: number): void;
textStyle(style: string): void;
stroke(color: string): void;
noStroke(): void;
}

export const TEXT_STYLE = 'bold'
export const TEXT_SIZE = 14

const sizeFactor = 50

function messageSizeLimit() {
Expand Down Expand Up @@ -63,12 +72,18 @@ function messageBackgroundPosition(drawer: MessageDrawer, message: DrawableMessa
function drawMessageBackground(drawer: MessageDrawer, message: DrawableMessage) {
const size = messageSize(drawer, message)
const position = messageBackgroundPosition(drawer, message)
drawer.fill('white')
drawer.rect(position.x, position.y, size.x, size.y, 0, 15, 10, 5)
}

export const drawMessage = (drawer: MessageDrawer) => (message: DrawableMessage): void => {
drawMessageBackground(drawer, message)
const position = messageTextPosition(drawer, message)
const limit = messageSizeLimit()
drawer.textSize(TEXT_SIZE)
drawer.textStyle(TEXT_STYLE)
drawer.fill('black')
drawer.textAlign('left')
drawer.noStroke()
drawer.text(message.message, position.x, position.y, limit.x, limit.y)
}
44 changes: 30 additions & 14 deletions src/test/game.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs'
import { buildEnvironment, WRENatives } from 'wollok-ts'
import interpret, { Interpreter } from 'wollok-ts/dist/interpreter/interpreter'
import { visualState, flushEvents, canvasResolution, wKeyCode, buildKeyPressEvent, queueEvent } from '../components/game/SketchUtils';
import { visualState, flushEvents, canvasResolution, wKeyCode, buildKeyPressEvent, queueEvent } from '../components/game/SketchUtils'
import { buildGameProject, GameProject, getProgramIn } from '../components/game/gameProject'
import { MessageDrawer, messageTextPosition } from '../components/game/messages'

Expand All @@ -25,19 +25,6 @@ const getVisualState = (interpreter: Interpreter, index = 0) => {
}

describe('game', () => {

gameTest('visualStates', 'pepita', ['games/pepita.wpgm'], function (interpreter) {
expect(getVisualState(interpreter)).toStrictEqual({
image: 'pepita.png',
position: { x: 1, y: 1 },
message: undefined,
})
})

gameTest('visualState should round a visuals position', 'visualStateTest', ['games/visualStateTest.wpgm'], function (interpreter) {
expect(getVisualState(interpreter).position).toStrictEqual({ x: 1, y: 2 })
})

gameTest('a visual outside of the canvas should be drawn', 'gameTest', ['games/gameTest.wpgm'], function (interpreter) {
expect(getVisualState(interpreter, 1)).toMatchObject({ image: 'out.png' })
})
Expand Down Expand Up @@ -116,6 +103,12 @@ describe('messages', () => {
textWidth: (text: string) => 5.5 * text.length,
rect: () => { },
text: () => { },
fill: () => { },
textAlign: () => { },
textSize: () => { },
textStyle: () => { },
stroke: () => { },
noStroke: () => { },
}

test('when a message is horizontally out of canvas, it should be inverted', () => {
Expand All @@ -135,6 +128,29 @@ describe('messages', () => {
})
})

describe('VisualState', () => {
gameTest('positionable visual', 'visualStateTest', ['games/visualStateTest.wpgm'], function (interpreter) {
expect(getVisualState(interpreter, 0)).toStrictEqual({
image: undefined,
position: { x: 1, y: 2 },
message: undefined,
text: undefined,
textColor: undefined,
})
})

gameTest('complete visual', 'visualStateTest', ['games/visualStateTest.wpgm'], function (interpreter) {
expect(getVisualState(interpreter, 1)).toStrictEqual({
image: 'anImage.png',
position: { x: 0, y: 0 },
message: undefined,
text: 'Sample text',
textColor: 'FF0000FF',
})
})

})

/*
describe('GameSound', () => {
Expand Down
23 changes: 19 additions & 4 deletions src/test/games/visualStateTest.wpgm
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import wollok.game.*

object myVisual{
object positionableVisual {
var property position = game.at(1.2, 1.8)

method image() = "noImage.png"
}

object completeVisual {

method position() = game.at(0, 0)

method image() = "anImage.png"

method text() = "Sample text"

method textColor() = "FF0000FF"
}

// object incompleteVisual {
// method image() = "anImage.png"
// }

program mockGame {
game.addVisual(myVisual)
// game.addVisual(incompleteVisual)
game.addVisual(positionableVisual)
game.addVisual(completeVisual)
game.start()
}

0 comments on commit dab9568

Please sign in to comment.