Repeating 2 backgrounds in Corona SDK - background

Here's a problem: I'm making a simple physics game using Corona SDK and very simple module: http://developer.coronalabs.com/code/move-camera So I've got fish object with physics body and in each frame (enterFrame event) I'm centering camera on it
camera.x = -fish.x + screenWidth / 2
And I've got two backgrounds bg1 and bg2, which tiled each after other (bg1 bg2 bg1 bg2 etc) will make nice moving-world effect without user knowing that there are only 2 backgrounds. The problem is I can't get right calculations of their positions to make such effect. I googled a lot, but can't find anything to fit my needs.
Here's a free art, which I'm using http://www.vickiwenderlich.com/2013/02/free-game-art-flying-goldfish/ There you can find these two backgrounds.
It's also possible that fish can go slightly in opposite direction (generally it's moving to the right so to make world-moving effect backgrounds has to move to the left) so it would be nice if it'll in calculations.
I figured out something like this (however it doesn't work but maybe I'm close):
local function updateFrame(event)
local m
local dfx = lfx - fish.x
lfx = fish.x
camera.x = -fish.x + screenWidth / 2
--print("dfx = " .. dfx)
bg1.x = bg1.x + dfx
bg2.x = bg2.x + dfx
s = s + dfx
if mAbs(s) > screenWidth then
m = sgn(s)
if m ~= 0 then
s = s - m * screenWidth
if m < 0 then
bg1.x = bg1.x - 2 * m * screenWidth
else
bg2.x = bg2.x - 2 * m * screenWidth
end
end
end
end
Runtime:addEventListener( "enterFrame", updateFrame );
s = screenLeft - screenWidth
where s is the sum of pixels moved and if it's over screenWidth I jump with one of the backgrounds, lfx is the last fish x location, dfx is a difference between last and current fish location and that's it.
If you can help me with my calculations or give me new ones or just give some interesting links please write them right here.
Any help will be appreciated,
Regards

local road = display.newImageRect( "Images/roadBg1.png",2247/4,559/4 )
road:setReferencePoint( display.CenterLeftReferencePoint )
road.x = 0
road.y = baseline - 20
local road2 = display.newImageRect( "Images/roadBg1.png",2247/4,559/4 )
road2:setReferencePoint( display.CenterLeftReferencePoint )
road2.x = 2247/4
road2.y = baseline - 20
local tPrevious = system.getTimer()
local function move(event)
local tDelta = event.time - tPrevious
tPrevious = event.time
local xOffset = ( 0.2 * tDelta )
road.x = road.x - xOffset
road2.x = road2.x - xOffset
if (road.x + road.contentWidth) < 0 then
road:translate( 2247/4 * 2, 0)
end
if (road2.x + road2.contentWidth) < 0 then
road2:translate( 2247/4 * 2, 0)
end
Runtime:addEventListener( "enterFrame", move )
or see the sample code of jungle scene game.
Location: SampleApps/Sprites/JungleScene

Try this:
local bg1 = display.newImageRect( "bg_1.png" ,480 ,320)
bg1.x = display.contentWidth/2; bg1.y = display.contentHeight/2
local bg2 = display.newImageRect( "bg_2.png" ,480 ,320 )
bg2.x = bg1.x + bg1.width; bg2.y = display.contentHeight/2
local speed = 30
function move()
bg1.x = bg1.x-speed;
bg2.x = bg2.x-speed;
if(bg1.x + bg1.width/2 < 0)then bg1.x = bg1.width*3/2-speed
elseif(bg2.x + bg2.width/2 < 0)then bg2.x = bg2.width*3/2-speed end
end
Runtime:addEventListener( "enterFrame", move )
Keep coding............ :)

Thanks #krs and #Malar, combining your answers I figured out how to do this:
local function updateFrame(event)
local speed = fish.x - lfx
lfx = fish.x
camera.x = -fish.x + screenWidth / 2
bg1.x = bg1.x - speed
bg2.x = bg2.x - speed
if bg1.x + bg1.width < 0 then
bg1.x = bg1.x + screenWidth * 2
end
if bg2.x + bg2.width < 0 then
bg2.x = bg2.x + screenWidth * 2
end
if bg1.x - bg1.width > 0 then
bg1.x = bg1.x - screenWidth * 2
end
if bg2.x - bg2.width > 0 then
bg2.x = bg2.x - screenWidth * 2
end
end
Runtime:addEventListener( "enterFrame", updateFrame );
Starting positions:
bg1.x = screenLeft
bg2.x = bg1.x + bg1.width
And the last most important change:
I put bg1, bg2 and camera into a group and other objects into camera group:
local camera = require("camera")
group = display.newGroup()
group:insert(bg1)
group:insert(bg2)
camera:insert(fish)
camera:insert(ground)
group:insert(camera)
So we have ground and fish, which can move forever, but the backgrounds are only moving from -screenWidth to screenWidth.
All these things combined works like a charm!

Related

Update parameters of a function in a while loop

I am trying to execute a while loop that holds a function with parameters. However, I have noticed that the parameters inside the while loop are not updated which leads to an infinite while loop. Is there a reason behind the fact that the function parameters are not being updated after every loop?
import shapefile
from osgeo import gdal
#import rasterio
print (gdal.VersionInfo())
def pointInRect(x, y, x1, y1, w, h): # check if a raster point is in another raster
x2, y2 = x1+w, y1+h
if (x1 < x and x < x2):
if (y1 < y and y < y2):
return True
return False
# Open the shapes centroids
shp_cntrds = 'Path to centroids'
sf_cntrds = shapefile.Reader(shp_cntrds)
shapes_cntrds = sf_cntrds.shapes()
records_cntrds = sf_cntrds.records()
# adjust labels position according to its shapes centroids position
for i in range(len(records_cntrds)):
print(i)
tods = gdal.Open(str(records_cntrds[i][1]))
width = tods.RasterXSize
height = tods.RasterYSize
tods.SetGeoTransform([shapes_cntrds[i].points[0][0] - (width * 0.005), 0.01, 0,
shapes_cntrds[i].points[0][1] + (height * 0.005), 0, -0.01])
gt = tods.GetGeoTransform()
left = gt[0]
bottom = gt[3] + width * gt[4] + height * gt[5]
right = gt[0] + width * gt[1] + height * gt[2]
top = gt[3]
srs = osr.SpatialReference()
srs.SetUTM(32, 1) # set crs
srs.SetWellKnownGeogCS('WGS84') # set crs
tods.SetProjection(srs.ExportToWkt()) # set Projection and save file
print(width, height)
tods = None
# iterate through Labels and move labels away from each others if they overlapp
for i in range(len(records_cntrds)):
tods1 = gdal.Open(str(records_cntrds[i][1])) # records of the centroid shapefile contains the raster file path
width = tods1.RasterXSize
height = tods1.RasterYSize
gt = tods1.GetGeoTransform()
left = gt[0]
bottom = gt[3] + width * gt[4] + height * gt[5]
right = gt[0] + width * gt[1] + height * gt[2]
top = gt[3]
face = [x for x in list(range(len(records_cntrds))) if x != i]
tods1 = None
for j in face:
if str(records_cntrds[i][1]) == str(records_cntrds[j][1]):
pass
else:
ds_raster_face = gdal.Open(str(records_cntrds[j][1]))
#print(str(records_cntrds[i][1]))
#print(str(records_cntrds[j][1]))
gt_face = ds_raster_face.GetGeoTransform()
width_face = ds_raster_face.RasterXSize
height_face = ds_raster_face.RasterYSize
left_face = gt_face[0]
bottom_face = gt_face[3] + width_face * gt_face[4] + height_face * gt_face[5]
right_face = gt_face[0] + width_face * gt_face[1] + height_face * gt_face[2]
top_face = gt_face[3]
width1 = width
left1 = left
height1 = height
bottom1 = bottom
while pointInRect(left_face, bottom_face, left1, bottom1, width1*0.01, height1*0.01) :
tods2 = gdal.Open(str(records_cntrds[i][1]))
gt = tods2.GetGeoTransform()
width1 = tods2.RasterXSize
height1 = tods2.RasterYSize
left1 = gt[0]
bottom1 = gt[3] + width1 * gt[4] + height1 * gt[5]
print("while executed")
tods2.SetGeoTransform([(shapes_cntrds[i].points[0][0] - (width1 * 0.005)) - 2.7, 0.01, 0,
(shapes_cntrds[i].points[0][1] + (height1 * 0.005)) - 2.8, 0, -0.01])
print("coordinates changed to",(i, left1, bottom1, width1, height1))
tods2 = None
The while loop should break when the function return false but it is repeating the same thing. Are the gt values not updatet or are they initialized again ?

Conversion ECEF XYZ to LLH (LAT/LONG/HEIGHT) and translation back - not accurate / possible error in IronPython script

I've modeled a 3D earth with gridpoints, as below:
The points are represented in 3D space as XYZ coordinates.
I then convert XYZ to Lat/Long/Height(elevation) based on the script I took from here:
JSFiddle
For some reason I got really strange results when trying to find XYZ of LLH not from my set, so I tried to verify the initial script by converting XYZ to LLH and then the same LLH back to XYZ to see if I get the same coordinate.
Instead, the resulting coordinate is some XYZ on earth, unrelated to the original XYZ position.
XYZ to LLH script:
Source: JSFiddle
def xyzllh(x,y,z):
""" xyz vector to lat,lon,height
output:
llhvec[3] with components
flat geodetic latitude in deg
flon longitude in deg
altkm altitude in km
"""
dtr = math.pi/180.0
rrnrm = [0.0] * 3
llhvec = [0.0] * 3
geodGBL()
esq = EARTH_Esq
rp = math.sqrt( x*x + y*y + z*z )
flatgc = math.asin( z / rp )/dtr
testval= abs(x) + abs(y)
if ( testval < 1.0e-10):
flon = 0.0
else:
flon = math.atan2( y,x )/dtr
if (flon < 0.0 ):
flon = flon + 360.0
p = math.sqrt( x*x + y*y )
# on pole special case
if ( p < 1.0e-10 ):
flat = 90.0
if ( z < 0.0 ):
flat = -90.0
altkm = rp - rearth(flat)
llhvec[0] = flat
llhvec[1] = flon
llhvec[2] = altkm
return llhvec
# first iteration, use flatgc to get altitude
# and alt needed to convert gc to gd lat.
rnow = rearth(flatgc)
altkm = rp - rnow
flat = gc2gd(flatgc,altkm)
rrnrm = radcur(flat)
rn = rrnrm[1]
for x in range(5):
slat = math.sin(dtr*flat)
tangd = ( z + rn*esq*slat ) / p
flatn = math.atan(tangd)/dtr
dlat = flatn - flat
flat = flatn
clat = math.cos( dtr*flat )
rrnrm = radcur(flat)
rn = rrnrm[1]
altkm = (p/clat) - rn
if ( abs(dlat) < 1.0e-12 ):
break
llhvec[0] = flat
llhvec[1] = flon
llhvec[2] = altkm
return llhvec
# globals
EARTH_A = 0
EARTH_B = 0
EARTH_F = 0
EARTH_Ecc = 0
EARTH_Esq = 0
# starting function do_llhxyz()
CallCount = 0
llh = [0.0] * 3
dtr = math.pi/180
CallCount = CallCount + 1
sans = " \n"
llh = xyzllh(x,y,z)
latitude = llh[0]
longitude= llh[1]
hkm = llh[2]
height = 1000.0 * hkm
latitude = fformat(latitude,5)
longitude = fformat(longitude,5)
height = fformat(height,1)
sans = sans +"Latitude,Longitude, Height (ellipsoidal) from ECEF\n"
sans = sans + "\n"
sans = sans +"Latitude : " + str(latitude) + " deg N\n"
sans = sans +"Longitude : " + str(longitude - 180) + " deg E\n"
sans = sans +"Height : " + str(height) + " m\n"
lats = []
longs = []
heights = []
lats.append(str(latitude))
longs.append(str(longitude - 180))
heights.append(str(height))
And this is the LLH to XYZ script:
Source: www.mathworks.com
a = 6378137
t = 8.1819190842622e-2
# (prime vertical radius of curvature)
N = a / math.sqrt(1 - (t*t) * (math.sin(lat)*math.sin(lat)))
x = []
y = []
z = []
# results:
x.append( ((N+height) * math.cos(lat) * math.cos(long))/1000 )
y.append( ((N+height) * math.cos(lat) * math.sin(long))/1000 )
z.append( (((1-t*t) * N + height) * math.sin(lat))/1000 )
Anyone know what I'm doing wrong here?
Thanks!

Files in Lua program not able to reference each other's variables

I'm hoping somebody experienced can point out where/if I am missing some crucial syntax.
My program works fine (because 95% of it was created by a CS50 professor), with one exception - I cannot seem to get the player and flag files/classes to reference each other to show that my Mario character has reached the final flag.
Specifically, the function "Flag:victory(player)" does not appear to be pulling information from the player file/class, while player has a similar function that is able to access Flag, although I don't see any difference between the two files as to why Flag is not behaving properly.
Flag = Class{}
function Flag:init(map)
-- reference to map for checking tiles
self.texture = map.spritesheet
-- animation frames
self.frames = {}
-- current animation frame
self.currentFrame = nil
self.player = Player(map)
-- used to determine behavior and animations
self.state = 'waving'
-- x and y velocity
self.dy = 0
-- position on top of map tiles
self.y = map.tileHeight * ((map.mapHeight / 2) - 4)
self.x = (map.mapWidth - 3) * map.tileWidth
-- initialize all player animations
self.animations = {
['waving'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(0, 48, 16, 16, self.texture:getDimensions()),
love.graphics.newQuad(16, 48, 16, 16, self.texture:getDimensions()),
love.graphics.newQuad(0, 48, 16, 16, self.texture:getDimensions()),
},
interval = 0.30
}),
['falling'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(32, 48, 16, 16, self.texture:getDimensions())
}
})
}
-- initialize animation and current frame we should render
self.animation = self.animations['waving']
self.currentFrame = self.animation:getCurrentFrame()
end
function Flag:update(dt)
self.animation:update(dt)
self.currentFrame = self.animation:getCurrentFrame()
self:victory()
end
function Flag:render()
local scaleX = - 1
-- draw sprite with scale factor and offsets
love.graphics.draw(self.texture, self.currentFrame, math.floor(self.x + 8 / 2),
math.floor(self.y + 8 / 2), 0, scaleX, 1, 8 / 2, 8 / 2)
end
function Flag:victory(player)
if self.player.victory == true then -- when player reaches flag
self.state = 'falling' -- change flag animation to down sprite
self.animation = self.animations['falling']
self.y = self.y + 2 -- descend the flag
end
end
--[[
Represents our player in the game, with its own sprite.
]]
Player = Class{}
local WALKING_SPEED = 140
local JUMP_VELOCITY = 400
function Player:init(map)
self.x = 0
self.y = 0
self.width = 16
self.height = 20
-- offset from top left to center to support sprite flipping
self.xOffset = 8
self.yOffset = 10
-- reference to map for checking tiles
self.map = map -- just a convenience because map comes in as a param/arg so the self should be dropped
self.texture = love.graphics.newImage('graphics/blue_alien.png')
-- sound effects
self.sounds = {
['jump'] = love.audio.newSource('sounds/jump.wav', 'static'),
['hit'] = love.audio.newSource('sounds/hit.wav', 'static'),
['coin'] = love.audio.newSource('sounds/coin.wav', 'static'),
}
-- variable for playing sound just once when game ends
self.musicplayed = false
-- animation frames
self.frames = {}
-- current animation frame
self.currentFrame = nil
-- used to determine behavior and animations
self.state = 'idle'
-- determines sprite flipping
self.direction = 'left'
-- x and y velocity
self.dx = 0
self.dy = 0
-- position on top of map tiles
self.y = map.tileHeight * ((map.mapHeight - 2) / 2) - self.height
self.x = map.tileWidth * 10
self.xmax = self.x -- farthest that mario has ever gone to the right
self.xmin = 1 -- farthest mario may go to the left, based on xmax and left border of map
-- initialize all player animations
self.animations = {
['idle'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions())
}
}),
['walking'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(128, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(144, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(160, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(144, 0, 16, 20, self.texture:getDimensions()),
},
interval = 0.15
}),
['jumping'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(32, 0, 16, 20, self.texture:getDimensions())
}
}),
['victory'] = Animation({
texture = self.texture,
frames = {
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(48, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(160, 0, 16, 20, self.texture:getDimensions()),
love.graphics.newQuad(0, 0, 16, 20, self.texture:getDimensions()),
},
interval = .25
})
}
-- initialize animation and current frame we should render
self.animation = self.animations['idle']
self.currentFrame = self.animation:getCurrentFrame()
-- behavior map we can call based on player state
self.behaviors = {
['idle'] = function(dt)
-- add spacebar functionality to trigger jump state
if love.keyboard.wasPressed('space') then
self.dy = -JUMP_VELOCITY
self.state = 'jumping'
self.animation = self.animations['jumping']
self.sounds['jump']:play()
elseif love.keyboard.isDown('left') then
self.direction = 'left'
self.dx = -WALKING_SPEED
self.state = 'walking'
self.animations['walking']:restart()
self.animation = self.animations['walking']
self:checkLeftBoundary()
elseif love.keyboard.isDown('right') then
self.direction = 'right'
self.dx = WALKING_SPEED
self.state = 'walking'
self.animations['walking']:restart()
self.animation = self.animations['walking']
else
self.dx = 0
end
self:checkLeftBoundary()
self:checkRightBoundary()
end,
['walking'] = function(dt)
-- keep track of input to switch movement while walking, or reset
-- to idle if we're not moving
if love.keyboard.wasPressed('space') then
self.dy = -JUMP_VELOCITY
self.state = 'jumping'
self.animation = self.animations['jumping']
self.sounds['jump']:play()
elseif love.keyboard.isDown('left') then
self.direction = 'left'
self.dx = -WALKING_SPEED
elseif love.keyboard.isDown('right') then
self.direction = 'right'
self.dx = WALKING_SPEED
else
self.dx = 0
self.state = 'idle'
self.animation = self.animations['idle']
end
self:checkLeftBoundary()
self:checkRightBoundary()
-- check for collisions moving left and right
self:checkRightCollision()
self:checkLeftCollision()
-- check if there's a tile directly beneath us
if not self.map:collides(self.map:tileAt(self.x, self.y + self.height)) and
not self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.state = 'jumping'
self.animation = self.animations['jumping']
end
end,
['jumping'] = function(dt)
if love.keyboard.isDown('left') then
self.direction = 'left'
self.dx = -WALKING_SPEED
elseif love.keyboard.isDown('right') then
self.direction = 'right'
self.dx = WALKING_SPEED
end
-- apply map's gravity before y velocity
self.dy = self.dy + self.map.gravity
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x, self.y + self.height)) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.dy = 0
self.state = 'idle'
self.animation = self.animations['idle']
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
self:checkLeftBoundary()
self:checkRightBoundary()
-- check for collisions moving left and right
self:checkRightCollision()
self:checkLeftCollision()
end,
['victory'] = function(dt)
self.dx = 0
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x, self.y + self.height)) or
self.map:collides(self.map:tileAt(self.x + self.width - 1, self.y + self.height)) then
-- if so, reset velocity and position and change state
self.dy = 0
self.y = (self.map:tileAt(self.x, self.y + self.height).y - 1) * self.map.tileHeight - self.height
end
end
}
end
function Player:update(dt)
self.behaviors[self.state](dt)
self.animation:update(dt)
self.currentFrame = self.animation:getCurrentFrame()
self.x = self.x + self.dx * dt
self.xmax = math.max(self.x, self.xmax) -- tester to update xmax if player moves further to right than ever before
self.xmin = math.max(1, math.min(self.xmax - VIRTUAL_WIDTH / 2, map.mapWidthPixels - VIRTUAL_WIDTH)) -- farthest mario may go to the left, based on xmax and left border of map
self:calculateJumps()
self:gameover()
self:reachflag()
if self.map:victory() == true then
self.victory = true
end
-- apply velocity
self.y = self.y + self.dy * dt
end
function Player:gameover()
if self.y > 300 then
self.game_over = true
end
end
function Player:reachflag(Flag)
if self.x >= flag.x then
self.victory = true
end
end
-- jumping and block hitting logic
function Player:calculateJumps()
-- if we have negative y velocity (jumping), check if we collide
-- with any blocks above us
if self.dy < 0 then
if self.map:tileAt(self.x, self.y).id ~= TILE_EMPTY or
self.map:tileAt(self.x + self.width - 1, self.y).id ~= TILE_EMPTY then
-- reset y velocity
self.dy = 0
-- change block to different block
local playCoin = false
local playHit = false
if self.map:tileAt(self.x, self.y).id == JUMP_BLOCK then
self.map:setTile(math.floor(self.x / self.map.tileWidth) + 1,
math.floor(self.y / self.map.tileHeight) + 1, JUMP_BLOCK_HIT)
playCoin = true
else
playHit = true
end
if self.map:tileAt(self.x + self.width - 1, self.y).id == JUMP_BLOCK then
self.map:setTile(math.floor((self.x + self.width - 1) / self.map.tileWidth) + 1,
math.floor(self.y / self.map.tileHeight) + 1, JUMP_BLOCK_HIT)
playCoin = true
else
playHit = true
end
if playCoin then
self.sounds['coin']:play()
elseif playHit then
self.sounds['hit']:play()
end
end
end
end
-- checks two tiles to our left to see if a collision occurred
function Player:checkLeftCollision()
if self.dx < 0 then
-- check if there's a tile directly beneath us
if self.map:collides(self.map:tileAt(self.x - 1, self.y)) or
self.map:collides(self.map:tileAt(self.x - 1, self.y + self.height - 1)) then
-- if so, reset velocity and position and change state
self.dx = 0
self.x = self.map:tileAt(self.x - 1, self.y).x * self.map.tileWidth
end
end
end
-- checks two tiles to our right to see if a collision occurred
function Player:checkRightCollision()
if self.dx > 0 then
-- check if there's a tile directly beneath us
if self.map:collides(map:tileAt(self.x + self.width, self.y)) or
self.map:collides(map:tileAt(self.x + self.width, self.y + self.height - 1)) then
-- if so, reset velocity and position and change state
self.dx = 0
self.x = (self.map:tileAt(self.x + self.width, self.y).x - 1) * map.tileWidth - self.width
end
end
end
function Player:checkLeftBoundary()
if self.x <= self.xmin then -- went too far left
self.x = self.xmin
if self.direction == 'left'then
self.dx = 0 -- set speed to zero but keep state, ie walking, jumping/falling
end
end
end
function Player:checkRightBoundary()
if self.x >= map.mapWidthPixels - 16 then -- went too far right
self.x = map.mapWidthPixels - 16
if self.direction == 'right'then
self.dx = 0 -- set speed to zero but keep state, ie walking, jumping/falling
end
end
end
function Player:render()
local scaleX
-- set negative x scale factor if facing left, which will flip the sprite
-- when applied
if self.direction == 'right' then
scaleX = 1
else
scaleX = -1
end
-- draw sprite with scale factor and offsets
love.graphics.draw(self.texture, self.currentFrame, math.floor(self.x + self.xOffset),
math.floor(self.y + self.yOffset), 0, scaleX, 1, self.xOffset, self.yOffset)
if self.game_over == true then
self.state = 'idle'
self.dy = 0
self.dx = 0
map.music:stop()
if self.musicplayed == false then
love.audio.newSource('sounds/Laser_Shoot2.wav', 'static'):play()
self.musicplayed = true
end
love.graphics.print('Oh Snap! Try again? (y/n)', self.xmin + 40, 40)
if love.keyboard.isDown('y') then
self.map:init()
self.map:render()
elseif love.keyboard.isDown('n')then
love.event.quit()
end
end
if self.victory == true then
self.state = 'victory'
self.animation = self.animations['victory']
if self.musicplayed == false then
love.audio.newSource('sounds/Powerup23.wav', 'static'):play()
self.musicplayed = true
end
love.graphics.print('Congratulations! Play again? (y/n)', self.xmin + 35, 40)
if love.keyboard.isDown('y') then
self.map:init()
self.map:render()
map.music:stop()
elseif love.keyboard.isDown('n')then
love.event.quit()
end
end
end
--[[
Super Mario Bros. Demo
Author: Colton Ogden
Original Credit: Nintendo
Demonstrates rendering a screen of tiles.
]]
Class = require 'class'
push = require 'push'
require 'Animation'
require 'Map'
require 'Player'
require 'Flag'
-- close resolution to NES but 16:9
VIRTUAL_WIDTH = 432
VIRTUAL_HEIGHT = 243
-- actual window resolution
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
-- seed RNG
math.randomseed(os.time())
-- makes upscaling look pixel-y instead of blurry
love.graphics.setDefaultFilter('nearest', 'nearest')
-- an object to contain our map data
map = Map()
flag = Flag(map)
player = Player(map)
-- performs initialization of all objects and data needed by program
function love.load()
-- sets up a different, better-looking retro font as our default
love.graphics.setFont(love.graphics.newFont('fonts/font.ttf', 16))
-- sets up virtual screen resolution for an authentic retro feel
push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, {
fullscreen = false,
resizable = true
})
love.window.setTitle('Super Mario 50')
love.keyboard.keysPressed = {}
love.keyboard.keysReleased = {}
end
-- called whenever window is resized
function love.resize(w, h)
push:resize(w, h)
end
-- global key pressed function
function love.keyboard.wasPressed(key)
if (love.keyboard.keysPressed[key]) then
return true
else
return false
end
end
-- global key released function
function love.keyboard.wasReleased(key)
if (love.keyboard.keysReleased[key]) then
return true
else
return false
end
end
-- called whenever a key is pressed
function love.keypressed(key)
if key == 'escape' then
love.event.quit()
end
love.keyboard.keysPressed[key] = true
end
-- called whenever a key is released
function love.keyreleased(key)
love.keyboard.keysReleased[key] = true
end
-- called every frame, with dt passed in as delta in time since last frame
function love.update(dt)
map:update(dt)
-- reset all keys pressed and released this frame
love.keyboard.keysPressed = {}
love.keyboard.keysReleased = {}
end
-- called each frame, used to render to the screen
function love.draw()
-- begin virtual resolution drawing
push:apply('start')
-- clear screen using Mario background blue
love.graphics.clear(108/255, 140/255, 255/255, 255/255)
-- renders our map object onto the screen
love.graphics.translate(math.floor(-map.camX + 0.5), math.floor(-map.camY + 0.5))
map:render()
-- end virtual resolution
push:apply('end')
end
--[[
Contains tile data and necessary code for rendering a tile map to the
screen.
]]
require 'Util'
Map = Class{}
TILE_BRICK = 1
TILE_EMPTY = -1
-- cloud tiles
CLOUD_LEFT = 6
CLOUD_RIGHT = 7
-- bush tiles
BUSH_LEFT = 2
BUSH_RIGHT = 3
-- mushroom tiles
MUSHROOM_TOP = 10
MUSHROOM_BOTTOM = 11
-- jump block
JUMP_BLOCK = 5
JUMP_BLOCK_HIT = 9
-- flagpole
FLAGPOLE_TOP = 8
FLAGPOLE_MIDDLE = 12
FLAGPOLE_BOTTOM = 16
PYRAMID_BLOCK = 17
-- a speed to multiply delta time to scroll map; smooth value
local SCROLL_SPEED = 62
-- constructor for our map object
function Map:init()
self.spritesheet = love.graphics.newImage('graphics/spritesheet.png')
self.sprites = generateQuads(self.spritesheet, 16, 16)
self.music = love.audio.newSource('sounds/music.wav', 'static')
self.pyramid_block = love.graphics.newImage('graphics/pyramidblock.png')
self.tileWidth = 16
self.tileHeight = 16
self.mapWidth = 300
self.mapHeight = 28
self.tiles = {}
-- applies positive Y influence on anything affected
self.gravity = 15
-- associate player with map
self.player = Player(self)
self.flag = Flag(self)
-- camera offsets
self.camX = 0
self.camY = -3
-- cache width and height of map in pixels
self.mapWidthPixels = self.mapWidth * self.tileWidth
self.mapHeightPixels = self.mapHeight * self.tileHeight
-- first, fill map with empty tiles
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
-- support for multiple sheets per tile; storing tiles as tables
self:setTile(x, y, TILE_EMPTY)
end
end
-- begin generating the terrain using vertical scan lines
local x = 1
while x < self.mapWidth - 20 do
-- 2% chance to generate a cloud
-- make sure we're 2 tiles from edge at least
if x < self.mapWidth - 2 then
if math.random(20) == 1 then
-- choose a random vertical spot above where blocks/pipes generate
local cloudStart = math.random(self.mapHeight / 2 - 6)
self:setTile(x, cloudStart, CLOUD_LEFT)
self:setTile(x + 1, cloudStart, CLOUD_RIGHT)
end
end
-- 5% chance to generate a mushroom
if math.random(20) == 1 then
-- left side of pipe
self:setTile(x, self.mapHeight / 2 - 2, MUSHROOM_TOP)
self:setTile(x, self.mapHeight / 2 - 1, MUSHROOM_BOTTOM)
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
-- next vertical scan line
x = x + 1
-- 10% chance to generate a bush, being sure to generate away from edge
elseif math.random(10) == 1 and x < self.mapWidth - 3 then
local bushLevel = self.mapHeight / 2 - 1
-- place bush component and then column of bricks
self:setTile(x, bushLevel, BUSH_LEFT)
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
x = x + 1
self:setTile(x, bushLevel, BUSH_RIGHT)
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
x = x + 1
-- 10% chance to not generate anything, creating a gap
elseif math.random(10) ~= 1 then
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
-- chance to create a block for Mario to hit
if math.random(15) == 1 then
self:setTile(x, self.mapHeight / 2 - 4, JUMP_BLOCK)
end
-- next vertical scan line
x = x + 1
else
-- increment X so we skip two scanlines, creating a 2-tile gap
x = x + 2
end
end
while x <= self.mapWidth do
-- draw in pyramid
if x == self.mapWidth - 13 then
local row = 1 -- how wide pyramid to be
while row < 7 do
local column = 1 -- might need to not say local everytime
while column <= row do
self:setTile(x, self.mapHeight / 2 - column, PYRAMID_BLOCK)
column = column + 1
end
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
row = row + 1
x = x + 1
end
end
-- draw in flagpole
if x == self.mapWidth - 2 then
self:setTile(x, self.mapHeight / 2 - 3, FLAGPOLE_TOP)
self:setTile(x, self.mapHeight / 2 - 2, FLAGPOLE_MIDDLE)
self:setTile(x, self.mapHeight / 2 - 1, FLAGPOLE_BOTTOM)
end
-- creates column of tiles going to bottom of map
for y = self.mapHeight / 2, self.mapHeight do
self:setTile(x, y, TILE_BRICK)
end
-- next vertical scan line
x = x + 1
end
-- start the background music
self.music:setLooping(true)
self.music:play()
end
-- return whether a given tile is collidable
function Map:collides(tile)
-- define our collidable tiles
local collidables = {
TILE_BRICK, JUMP_BLOCK, JUMP_BLOCK_HIT,
MUSHROOM_TOP, MUSHROOM_BOTTOM, PYRAMID_BLOCK
}
-- iterate and return true if our tile type matches
for _, v in ipairs(collidables) do
if tile.id == v then
return true
end
end
return false
end
-- this function doesn't appear to be doing anything...
function Map:victory(player, flag)
if self.player.x >= self.flag.x * map.tileWidth then
return true
else
return false
end
end
-- function to update camera offset with delta time
function Map:update(dt)
self.player:update(dt)
self.flag:update(dt)
-- keep camera's X coordinate following the player, preventing camera from
-- scrolling past 0 to the left and the map's width
self.camX = math.min(self.mapWidthPixels - VIRTUAL_WIDTH, math.max(self.camX, math.min(self.player.x - VIRTUAL_WIDTH / 2,
math.min(self.mapWidthPixels - VIRTUAL_WIDTH, self.player.x))))
end
-- gets the tile type at a given pixel coordinate
function Map:tileAt(x, y)
return {
x = math.floor(x / self.tileWidth) + 1,
y = math.floor(y / self.tileHeight) + 1,
id = self:getTile(math.floor(x / self.tileWidth) + 1, math.floor(y / self.tileHeight) + 1)
}
end
-- returns an integer value for the tile at a given x-y coordinate
function Map:getTile(x, y)
return self.tiles[(y - 1) * self.mapWidth + x]
end
-- sets a tile at a given x-y coordinate to an integer value
function Map:setTile(x, y, id)
self.tiles[(y - 1) * self.mapWidth + x] = id
end
-- renders our map to the screen, to be called by main's render
function Map:render()
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
local tile = self:getTile(x, y)
if tile ~= TILE_EMPTY then
if tile > 16 then
love.graphics.draw(self.pyramid_block,
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
else
love.graphics.draw(self.spritesheet, self.sprites[tile],
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
end
end
end
end
self.player:render()
self.flag:render()
end
You're using 'self.player' which is a brand new player at the init() (which is a different player than the one you want)
You need to use 'player' that you passed as an argument to check if player.victory is true.

Can't figure out, why script on Jython working differently from script on Pascal

Long story short: I'm writing script, which should move mouse and do clicks like human (it's a bot, actually), using SikuliX. SikuliX uses Jython 2.7 as lang for scritps.
I found nice lib for my purposes (moving mouse like human): mouse.simba written in Pascal-like lang, and rewrite function _humanWindMouse() in jython. It works, but not like I expected it would be.
Test run of my script, drawing rectangle:
https://prtscr.cx.ua/storage/5b/5b2203.jpg
Result of using original function with same coords:
https://prtscr.cx.ua/storage/bb/bb3ff5.jpg
sorry for links, I can't post images yet (
My code:
import random
import time
import math
from time import sleep
from math import sqrt
from math import ceil
from math import hypot
from java.awt import Robot
def distance(x1, y1, x2, y2):
return math.hypot(x2 - x1, y2 - y1)
def myrandom(x):
return random.randint(0, x-1)
def myround(x):
return int(round(x))
# function MMouseMove (MyMouseMove) for moving mouse using only coord
def MMouseMove(x,y):
robot = Robot()
robot.mouseMove(x,y)
# function HumanWindMouse by BenLand100 & Flight, python implementation
def humanWindMouse(xs, ys, xe, ye, gravity, wind):
veloX = veloY = windX=windY=veloMag=dist=randomDist=lastDist=D=0
lastX=lastY=MSP=W=TDist=0
mouseSpeed = 20
MSP = mouseSpeed
sqrt2 = sqrt(2)
sqrt3 = sqrt(3)
sqrt5 = sqrt(5)
TDist = distance(myround(xs), myround(ys), myround(xe), myround(ye))
t = time.time() + 10000
while True:
if time.time() > t:
break
dist = hypot(xs - xe, ys - ye)
wind = min(wind, dist)
if dist < 1:
dist = 1
D = (myround((myround(TDist)*0.3))/7)
if D > 25:
D = 25
if D < 5:
D = 5
rCnc = myrandom(6)
if rCnc == 1:
D = random.randint(2,3)
if D <= myround(dist):
maxStep = D
else:
maxStep = myround(dist)
windX= windX / sqrt2
windY= windY / sqrt2
veloX= veloX + windX
veloY= veloY + windY
veloX= veloX + gravity * (xe - xs) / dist
veloY= veloY + gravity * (ye - ys) / dist
if hypot(veloX, veloY) > maxStep:
temp = int(myround(maxStep) // 2)
if temp == 0:
temp = 1
randomDist= maxStep / 2.0 + myrandom(temp)
veloMag= sqrt(veloX * veloX + veloY * veloY)
veloX= (veloX / veloMag) * randomDist
veloY= (veloY / veloMag) * randomDist
lastX= myround(xs)
lastY= myround(ys)
xs= xs + veloX
ys= ys + veloY
if lastX <> myround(xs) or lastY <> myround(ys):
MMouseMove(myround(xs), myround(ys))
W = (myrandom((myround(100/MSP)))*6)
if W < 5:
W = 5
W = myround(W*0.9)
sleep(W/1000.0)
lastdist= dist
if hypot(xs - xe, ys - ye) < 1:
break
if myround(xe) <> myround(xs) or myround(ye) <> myround(ys):
MMouseMove(myround(xe), myround(ye))
mouseSpeed = MSP
return;
def MMouse(x,y):
mouseSpeed = 20
randSpeed = (myrandom(mouseSpeed) / 2.0 + mouseSpeed) / 10.0
curPos = Mouse.at()
x1 = curPos.x
y1 = curPos.y
humanWindMouse(x1, y1, x, y, 5, 10.0/randSpeed)
return;
And I used this in such a way:
MMouseMove(227, 146)
mouseDown(Button.LEFT)
MMouse(396, 146)
MMouse(396, 252)
MMouse(227, 252)
MMouse(227, 146)
mouseUp(Button.LEFT)
exit()
mouseDown() and mouseUp() are built-in functions in SikuliX
And I didn't use built-in mouseMove(), because with it going from A to B is too slow.
Any help would be appreciated
After few hours of debugging i figured out the problem: in source code for unknowing reason author passed constant called MOUSE_HUMAN to variable named gravity when caling his function _humanWindMouse(), this looks like an error to me. Thats why I decided to fix this in my code, and throw out one argument of the function and a few lines of code (and that was wrong move). After re-adding needed code my function working, as I expected.
So, here's the working code:
# function HumanWindMouse by BenLand100 & Flight,
# python implementation by Nokse
def humanWindMouse(xs, ys, xe, ye, gravity, wind, targetArea):
veloX = veloY = windX=windY=veloMag=dist=randomDist=lastDist=D=0
lastX=lastY=MSP=W=TDist=0
mouseSpeed = 20
MSP = mouseSpeed
sqrt2 = sqrt(2)
sqrt3 = sqrt(3)
sqrt5 = sqrt(5)
TDist = distance(myround(xs), myround(ys), myround(xe), myround(ye))
t = time.time() + 10000
while True:
if time.time() > t:
break
dist = hypot(xs - xe, ys - ye)
wind = min(wind, dist)
if dist < 1:
dist = 1
D = (myround((myround(TDist)*0.3))/7)
if D > 25:
D = 25
if D < 5:
D = 5
rCnc = myrandom(6)
if rCnc == 1:
D = random.randint(2,3)
if D <= myround(dist):
maxStep = D
else:
maxStep = myround(dist)
if dist >= targetArea:
windX = windX / sqrt3 + (myrandom(myround(wind) * 2 + 1) - wind) / sqrt5
windY = windY / sqrt3 + (myrandom(myround(wind) * 2 + 1) - wind) / sqrt5
else:
windX = windX / sqrt2
windY = windY / sqrt2
veloX = veloX + windX
veloY = veloY + windY
veloX = veloX + gravity * (xe - xs) / dist
veloY = veloY + gravity * (ye - ys) / dist
if hypot(veloX, veloY) > maxStep:
halfSteps = int(myround(maxStep) // 2)
if halfSteps == 0:
halfSteps = 1
randomDist = maxStep / 2.0 + myrandom(halfSteps)
veloMag = sqrt(veloX * veloX + veloY * veloY)
veloX = (veloX / veloMag) * randomDist
veloY = (veloY / veloMag) * randomDist
lastX = myround(xs)
lastY = myround(ys)
xs = xs + veloX
ys = ys + veloY
if lastX <> myround(xs) or lastY <> myround(ys):
MMouseMove(myround(xs), myround(ys))
W = (myrandom((myround(100/MSP)))*6)
if W < 5:
W = 5
W = myround(W*0.9)
sleep(W/1000.0)
lastdist = dist
#condition for exiting while loop
if hypot(xs - xe, ys - ye) < 1:
break
if myround(xe) <> myround(xs) or myround(ye) <> myround(ys):
MMouseMove(myround(xe), myround(ye))
mouseSpeed = MSP
return;
I tested it with different parameters, and choose this one:
humanWindMouse(xs, ys, x, y, 9, 10.0/randSpeed, 10.0*randSpeed)
but I recommend to play with parameters first, to understand, how do they affect the behavior of the mouse.
How to calc randSpeed, what should be imported, and sub-functions, such as myround(), could be found at my first post.
Hope, this code will help somebody someday)

Stopping at a point

I have a space ship that I want to turn to a destination angle. Currently it works like 90% of the time, but sometimes, it 'jumps' to the destination angle rather than moving smoothly. Here is my code:
a = System.Math.Sin(.destStoppingAngle + System.Math.PI)
b = System.Math.Cos(.destStoppingAngle + System.Math.PI)
c = System.Math.Sin(.msngFacing)
d = System.Math.Cos(.msngFacing)
det = a * d - b * c
If det > 0 Then
.msngFacing = .msngFacing - .ROTATION_RATE * TV.TimeElapsed
If det < 0.1 Then
.msngFacing = .destStoppingAngle
.turning = False
End If
Else
.msngFacing = .msngFacing + .ROTATION_RATE * TV.TimeElapsed
If det > 0.1 Then
.msngFacing = .destStoppingAngle
.turning = False
End If
End If
I would do it like this. First you need a function to lerp an angle (C code, port it yourself):
float lerpangle(float from, float to, float frac) {
float a;
if ( to - from > 180 ) {
to -= 360;
}
if ( to - from < -180 ) {
to += 360;
}
a = from + frac * (to - from);
return a;
}
Then, when starting the rotation you have the duration and stoppingangle as your own parameters. Get the startingangle from your object and startingtime (in something decently precise, milliseconds) and save them. The rotation then goes like this:
current_rotation = lerpangle(startingangle, stoppingangle,
(time.now - startingtime) / duration)